---
keywords:
- containers
- types
- container types
- single type
- array
- schema definition file
description: You can add a typedefs section to the schema definition file, where you can define a single type name for a container type. This way you can easily create containers that contain container types.
image: /img/logo/WASP_logo_dark.png
---
import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"

# Type Definitions

Since we allow nesting of [container types](../wasm_vm/proxies.mdx#container-proxies), it
is a difficult to create proper declarations for such nested types. Especially because you
can only indicate either a single type, or an array of single type, or a map of single
type in a field definition.

There is a simple solution to this problem. You can add a `typedefs` section to the
schema definition file, where you can define a single type name for a container type. That
way you can easily create containers that contain such container types. The schema tool
will automatically generate the in-between proxy types necessary to make this work.

To keep it at the `betting` smart contract from [the previous section](structs.mdx),
imagine you want to keep track of all betting rounds. Since a betting round contains an
array of all bets in a round, if it weren't for typedefs you could not define it easily.

Instead, now you add the following to your schema definition file:

<Tabs defaultValue="yaml"
      values={[
          {label: 'schema.yaml', value: 'yaml'},
          {label: 'schema.json', value: 'json'},
      ]}>

<TabItem value="json">

```json
{
  "typedefs": {
    "BettingRound": "Bet[] // one round of bets"
  },
  "state": {
    "rounds": "BettingRound[] // keep track of all betting rounds"
  }
}
```

</TabItem>

<TabItem value="yaml">

```yaml
typedefs:
  BettingRound: Bet[] // one round of bets
state:
  rounds: BettingRound[] // keep track of all betting rounds
```

</TabItem>
</Tabs>

The schema tool will generate the following proxies in `typedefs.xx`:

<Tabs defaultValue="go"
	values={[
		{label: 'Go', value: 'go'},
		{label: 'Rust', value: 'rust'},
	]}>

<TabItem value="go">

```go
package betting

import "github.com/iotaledger/wasp/packages/vm/wasmlib"

type ImmutableBettingRound = ArrayOfImmutableBet

type ArrayOfImmutableBet struct {
    objID int32
}

func (a ArrayOfImmutableBet) Length() int32 {
    return wasmlib.GetLength(a.objID)
}

func (a ArrayOfImmutableBet) GetBet(index int32) ImmutableBet {
    return ImmutableBet{objID: a.objID, keyID: wasmlib.Key32(index)}
}

type MutableBettingRound = ArrayOfMutableBet

type ArrayOfMutableBet struct {
    objID int32
}

func (a ArrayOfMutableBet) Clear() {
    wasmlib.Clear(a.objID)
}

func (a ArrayOfMutableBet) Length() int32 {
    return wasmlib.GetLength(a.objID)
}

func (a ArrayOfMutableBet) GetBet(index int32) MutableBet {
    return MutableBet{objID: a.objID, keyID: wasmlib.Key32(index)}
}
```

</TabItem>
<TabItem value="rust">

```rust
use wasmlib::*;
use wasmlib::host::*;

use crate::types::*;

pub type ImmutableBettingRound = ArrayOfImmutableBet;

pub struct ArrayOfImmutableBet {
    pub(crate) obj_id: i32,
}

impl ArrayOfImmutableBet {
    pub fn length(&self) -> i32 {
        get_length(self.obj_id)
    }

    pub fn get_bet(&self, index: i32) -> ImmutableBet {
        ImmutableBet { obj_id: self.obj_id, key_id: Key32(index) }
    }
}

pub type MutableBettingRound = ArrayOfMutableBet;

pub struct ArrayOfMutableBet {
    pub(crate) obj_id: i32,
}

impl ArrayOfMutableBet {
    pub fn clear(&self) {
        clear(self.obj_id);
    }

    pub fn length(&self) -> i32 {
        get_length(self.obj_id)
    }

    pub fn get_bet(&self, index: i32) -> MutableBet {
        MutableBet { obj_id: self.obj_id, key_id: Key32(index) }
    }
}
```

</TabItem>
<TabItem value="ts">

```ts
import * as wasmlib from "wasmlib"
import * as sc from "./index";

export class ImmutableBettingRound extends ArrayOfImmutableBet {
};

export class ArrayOfImmutableBet {
    objID: i32;

    constructor(objID: i32) {
        this.objID = objID;
    }

    length(): i32 {
        return wasmlib.getLength(this.objID);
    }

    getBet(index: i32): sc.ImmutableBet {
        return new sc.ImmutableBet(this.objID, new wasmlib.Key32(index));
    }
}

export class MutableBettingRound extends ArrayOfMutableBet {
};

export class ArrayOfMutableBet {
    objID: i32;

    constructor(objID: i32) {
        this.objID = objID;
    }

    clear(): void {
        wasmlib.clear(this.objID);
    }

    length(): i32 {
        return wasmlib.getLength(this.objID);
    }

    getBet(index: i32): sc.MutableBet {
        return new sc.MutableBet(this.objID, new wasmlib.Key32(index));
    }
}
```

</TabItem>
</Tabs>

Note how ImmutableBettingRound and MutableBettingRound type aliases are created for the
types ArrayOfImmutableBet and ArrayOfMutableBet. These are subsequently used in the state
definition in `state.xx`:

<Tabs defaultValue="go"
      groupId="language"
      values={[
          {label: 'Go', value: 'go'},
          {label: 'Rust', value: 'rust'},
          {label: 'TypeScript', value: 'ts'},
      ]}>

<TabItem value="go">

```go
package betting

import "github.com/iotaledger/wasp/packages/vm/wasmlib"

type ArrayOfImmutableBettingRound struct {
    objID int32
}

func (a ArrayOfImmutableBettingRound) Length() int32 {
    return wasmlib.GetLength(a.objID)
}

func (a ArrayOfImmutableBettingRound) GetBettingRound(index int32) ImmutableBettingRound {
    subID := wasmlib.GetObjectID(a.objID, wasmlib.Key32(index), wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES)
    return ImmutableBettingRound{objID: subID}
}

type ImmutableBettingState struct {
    id int32
}

func (s ImmutableBettingState) Bets() ArrayOfImmutableBet {
    arrID := wasmlib.GetObjectID(s.id, idxMap[IdxStateBets], wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES)
    return ArrayOfImmutableBet{objID: arrID}
}

func (s ImmutableBettingState) Owner() wasmlib.ScImmutableAgentID {
    return wasmlib.NewScImmutableAgentID(s.id, idxMap[IdxStateOwner])
}

func (s ImmutableBettingState) Rounds() ArrayOfImmutableBettingRound {
    arrID := wasmlib.GetObjectID(s.id, idxMap[IdxStateRounds], wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES)
    return ArrayOfImmutableBettingRound{objID: arrID}
}

type ArrayOfMutableBettingRound struct {
    objID int32
}

func (a ArrayOfMutableBettingRound) Clear() {
    wasmlib.Clear(a.objID)
}

func (a ArrayOfMutableBettingRound) Length() int32 {
    return wasmlib.GetLength(a.objID)
}

func (a ArrayOfMutableBettingRound) GetBettingRound(index int32) MutableBettingRound {
    subID := wasmlib.GetObjectID(a.objID, wasmlib.Key32(index), wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES)
    return MutableBettingRound{objID: subID}
}

type MutableBettingState struct {
    id int32
}

func (s MutableBettingState) Bets() ArrayOfMutableBet {
    arrID := wasmlib.GetObjectID(s.id, idxMap[IdxStateBets], wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES)
    return ArrayOfMutableBet{objID: arrID}
}

func (s MutableBettingState) Owner() wasmlib.ScMutableAgentID {
    return wasmlib.NewScMutableAgentID(s.id, idxMap[IdxStateOwner])
}

func (s MutableBettingState) Rounds() ArrayOfMutableBettingRound {
    arrID := wasmlib.GetObjectID(s.id, idxMap[IdxStateRounds], wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES)
    return ArrayOfMutableBettingRound{objID: arrID}
}
```

</TabItem>
<TabItem value="rust">

```rust
use wasmlib::*;
use wasmlib::host::*;

use crate::*;
use crate::keys::*;
use crate::typedefs::*;
use crate::types::*;

pub struct ArrayOfImmutableBettingRound {
    pub(crate) obj_id: i32,
}

impl ArrayOfImmutableBettingRound {
    pub fn length(&self) -> i32 {
        get_length(self.obj_id)
    }

    pub fn get_betting_round(&self, index: i32) -> ImmutableBettingRound {
        let sub_id = get_object_id(self.obj_id, Key32(index), TYPE_ARRAY | TYPE_BYTES)
        ImmutableBettingRound { obj_id: sub_id }
    }
}

#[derive(Clone, Copy)]
pub struct ImmutableBettingState {
    pub(crate) id: i32,
}

impl ImmutableBettingState {
    pub fn bets(&self) -> ArrayOfImmutableBet {
        let arr_id = get_object_id(self.id, idx_map(IDX_STATE_BETS), TYPE_ARRAY | TYPE_BYTES);
        ArrayOfImmutableBet { obj_id: arr_id }
    }

    pub fn owner(&self) -> ScImmutableAgentID {
        ScImmutableAgentID::new(self.id, idx_map(IDX_STATE_OWNER))
    }

    pub fn rounds(&self) -> ArrayOfImmutableBettingRound {
        let arr_id = get_object_id(self.id, idx_map(IDX_STATE_ROUNDS), TYPE_ARRAY | TYPE_BYTES);
        ArrayOfImmutableBettingRound { obj_id: arr_id }
    }
}

pub struct ArrayOfMutableBettingRound {
    pub(crate) obj_id: i32,
}

impl ArrayOfMutableBettingRound {
    pub fn clear(&self) {
        clear(self.obj_id);
    }

    pub fn length(&self) -> i32 {
        get_length(self.obj_id)
    }

    pub fn get_betting_round(&self, index: i32) -> MutableBettingRound {
        let sub_id = get_object_id(self.obj_id, Key32(index), TYPE_ARRAY | TYPE_BYTES)
        MutableBettingRound { obj_id: sub_id }
    }
}

#[derive(Clone, Copy)]
pub struct MutableBettingState {
    pub(crate) id: i32,
}

impl MutableBettingState {
    pub fn bets(&self) -> ArrayOfMutableBet {
        let arr_id = get_object_id(self.id, idx_map(IDX_STATE_BETS), TYPE_ARRAY | TYPE_BYTES);
        ArrayOfMutableBet { obj_id: arr_id }
    }

    pub fn owner(&self) -> ScMutableAgentID {
        ScMutableAgentID::new(self.id, idx_map(IDX_STATE_OWNER))
    }

    pub fn rounds(&self) -> ArrayOfMutableBettingRound {
        let arr_id = get_object_id(self.id, idx_map(IDX_STATE_ROUNDS), TYPE_ARRAY | TYPE_BYTES);
        ArrayOfMutableBettingRound { obj_id: arr_id }
    }
}
```

</TabItem>
<TabItem value="ts">

```ts
import * as wasmlib from "wasmlib"
import * as sc from "./index";

export class ArrayOfImmutableBettingRound {
    objID: i32;

    constructor(objID: i32) {
        this.objID = objID;
    }

    length(): i32 {
        return wasmlib.getLength(this.objID);
    }

    getBettingRound(index: i32): sc.ImmutableBettingRound {
        let subID = wasmlib.getObjectID(this.objID, new wasmlib.Key32(index), wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES);
        return new sc.ImmutableBettingRound(subID);
    }
}

export class ImmutableBettingState extends wasmlib.ScMapID {
    bets(): sc.ArrayOfImmutableBet {
        let arrID = wasmlib.getObjectID(this.mapID, sc.idxMap[sc.IdxStateBets], wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES);
        return new sc.ArrayOfImmutableBet(arrID)
    }

    owner(): wasmlib.ScImmutableAgentID {
        return new wasmlib.ScImmutableAgentID(this.mapID, sc.idxMap[sc.IdxStateOwner]);
    }

    rounds(): sc.ArrayOfImmutableBettingRound {
        let arrID = wasmlib.getObjectID(this.mapID, sc.idxMap[sc.IdxStateRounds], wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES);
        return new sc.ArrayOfImmutableBettingRound(arrID)
    }
}

export class ArrayOfMutableBettingRound {
    objID: i32;

    constructor(objID: i32) {
        this.objID = objID;
    }

    clear(): void {
        wasmlib.clear(this.objID);
    }

    length(): i32 {
        return wasmlib.getLength(this.objID);
    }

    getBettingRound(index: i32): sc.MutableBettingRound {
        let subID = wasmlib.getObjectID(this.objID, new wasmlib.Key32(index), wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES);
        return new sc.MutableBettingRound(subID);
    }
}

export class MutableBettingState extends wasmlib.ScMapID {
    bets(): sc.ArrayOfMutableBet {
        let arrID = wasmlib.getObjectID(this.mapID, sc.idxMap[sc.IdxStateBets], wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES);
        return new sc.ArrayOfMutableBet(arrID)
    }

    owner(): wasmlib.ScMutableAgentID {
        return new wasmlib.ScMutableAgentID(this.mapID, sc.idxMap[sc.IdxStateOwner]);
    }

    rounds(): sc.ArrayOfMutableBettingRound {
        let arrID = wasmlib.getObjectID(this.mapID, sc.idxMap[sc.IdxStateRounds], wasmlib.TYPE_ARRAY|wasmlib.TYPE_BYTES);
        return new sc.ArrayOfMutableBettingRound(arrID)
    }
}
```

</TabItem>
</Tabs>

Notice how the rounds() member function returns a proxy to an array of BettingRound.
Which in turn is an array of Bet. So, the desired result has been achieved. And every
access step along the way only allows you to take the path laid out which is checked at
compile-time.

In the next section we will explore how the schema tool generates a proxy interface for
mutable [states](state.mdx).